package br.edu.ufcg.dsc.adsd.lotv.core.entites;

import java.util.ArrayList;
import java.util.List;

import br.edu.ufcg.dsc.adsd.lotv.core.Connectable;
import br.edu.ufcg.dsc.adsd.lotv.core.LANPackage;
import br.edu.ufcg.dsc.adsd.lotv.utils.Constants;
import eduni.simjava.Sim_entity;
import eduni.simjava.Sim_event;
import eduni.simjava.Sim_system;
import eduni.simjava.distributions.Sim_negexp_obj;

public class LAN extends Connectable {

	private List<String> devices;
	private Sim_negexp_obj delayer;

	public LAN(String name, double mean) {
		super(name);
		this.delayer = new Sim_negexp_obj(name + Constants.DISTRIBUTION_NAME, mean);
		this.add_generator(this.delayer);
		this.devices = new ArrayList<String>();
	}
	
	@Override
	public String connect(Sim_entity to) {
		//Meio podrão... Não estou lembrando do pattern que usa pra evitar isso
		String port = super.connect(to);
		this.devices.add(port);
		return port;
	}
	
	
	private void route(Sim_event info) {
		//Essa LAN tá meio demente, só faz UNICAST ou BROADCAST
		LANPackage pkg = LANPackage.extract(info);
		switch (info.get_tag()) {
			case Constants.BROADCAST:
				broadcast(pkg);
				break;
			case Constants.UNICAST:
				unicast(pkg);
				break;
			default:
				break;
		}
	}

	private void unicast(LANPackage pkg) {
		String port = Constants.FROM_NAME + this.get_name() 
						+ Constants.TO_NAME + pkg.getDst();
		this.sim_process(this.delayer.sample());
		this.sim_schedule(port, 0.0, Constants.UNICAST, pkg);
	}

	private void broadcast(LANPackage pkg) {
		this.sim_process(this.delayer.sample());
		for(String port : this.devices) {
			this.sim_schedule(port, 0.0, Constants.BROADCAST, pkg);
		}
	}
	
	@Override
	public void body() {
		System.out.println("LAN ID:" + this.get_id() + " - Ports: " + this.ports);
		while(Sim_system.running()) {
			Sim_event e = new Sim_event();
			this.sim_get_next(e);
			this.route(e);
			this.sim_completed(e);
		}
		
	}

}
